iT邦幫忙

2024 iThome 鐵人賽

DAY 14
0
Modern Web

使用Nextjs及Xata全端開發 打造屬於你的討論版SaaS系列 第 14

[Day14] 修改service的api - Nextjs的身份驗證

  • 分享至 

  • xImage
  •  

我們今天要來實作修改Service的api

先實作驗證使用者登入身份的middleware

建立src/lib/middleware/serviceOwnerCheck.ts

import { NextRequest, NextResponse } from "next/server";
import { Session } from "next-auth";
import { auth } from "@/auth";

import { XataClient, ServicesRecord } from "@/xata";

export interface NextAuthRequest extends NextRequest {
  auth: Session | null;
}

export const handleRole = (handler: Function) => {
  return auth(async (req: NextAuthRequest, context: any) => {
    const serviceId = context.params.serviceId;
    const xata = new XataClient({
      branch: serviceId,
      apiKey: process.env.XATA_API_KEY,
    });
    const service = await xata.db.services.getFirst();
    if (!service) {
      return NextResponse.json({ error: "Service not found" }, { status: 404 });
    }
    const isOwner = req.auth?.user?.id === "admin";
    return handler(req, { ...context, xata, service, isOwner });
  });
};

export interface ServiceRoleContext {
  xata: XataClient;
  service: ServicesRecord;
  isOwner: boolean;
}

export const withServiceOwnerCheck = (handler: Function) => {
  return handleRole(
    async (req: NextAuthRequest, context: ServiceRoleContext) => {
      if (!context.isOwner) {
        return NextResponse.json(
          { error: "You are not owner of service" },
          { status: 403 }
        );
      }
      return handler(req, context);
    }
  );
};

export type ServiceOwnerContext = ServiceRoleContext;

實作修改Service的api

在你的src/app/api/service/[serviceId]/route.ts中,我們需要實作PUT的api,用來修改service的資料

import { NextResponse } from "next/server";
import { ILinkItem } from "@/components/layout/Title";
import { NextAuthRequest } from "@/auth";
import {
  withServiceOwnerCheck,
  ServiceOwnerContext,
} from "@/lib/middleware/serviceOwnerCheck";

const put = async (req: NextAuthRequest, context: ServiceOwnerContext) => {
  try {
    const { xata, service } = context;

    const data = await req.json();
    const name = data.name as string;
    const description = data.description as string;
    const topLinks = data.topLinks as ILinkItem;
    const headLinks = data.headLinks as ILinkItem;

    await xata.db.services.update(service.id, {
      name: name.trim(),
      description,
      topLinks: topLinks || [],
      headLinks: headLinks || [],
    });

    return NextResponse.json({
      message: "Service updated successfully",
    });
  } catch (error: any) {
    console.error("Service update error:", error);
    return NextResponse.json(
      { error: "Service update failed: " + error.message },
      { status: 500 }
    );
  }
};

export const PUT = withServiceOwnerCheck(put);

然後 你就可以在

http://localhost:3000/dashboard/main

中更新service的資料了

修改之後 你可以到

http://localhost:3000/service/main

這裡去看你剛剛修改的資料是否已經正確的被顯示出來

觀念解釋

今天的實作中

我們實作了兩個middleware

  1. handleRole
  2. withServiceOwnerCheck

handleRole

我們這裡會實作一個XataClient的實體
並確認service是否存在
以及登入的人是否為admin

const xata = new XataClient({
  branch: serviceId,
  apiKey: process.env.XATA_API_KEY,
});

const service = await xata.db.services.getFirst();
if (!service) {
  return NextResponse.json({ error: "Service not found" }, { status: 404 });
}
const isOwner = req.auth?.user?.id === "admin";

並且定義了context的型別

export interface ServiceRoleContext {
  xata: XataClient;
  service: ServicesRecord;
  isOwner: boolean;
}

這樣在withServiceOwnerCheck中 我們就可以使用這個context了

async (req: NextAuthRequest, context: ServiceRoleContext) => {
  if (!context.isOwner) { // 如果使用者不是owner 回傳403
    return NextResponse.json(
      { error: "You are not owner of service" },
      { status: 403 }
    );
  }
  return handler(req, context);
}

而由於我們已經在middleware中實作過xataclient了

因此在我們的api中 就可以直接拿出來用

const { xata, service } = context;

明天我們繼續優化一些小功能


上一篇
[Day13] 建立管理後台 - Nextjs的auth, authjs
下一篇
[Day15] 回報機制
系列文
使用Nextjs及Xata全端開發 打造屬於你的討論版SaaS30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言